/**
 * 自定义crypto模块，为微信小程序提供加密功能
 * 由于小程序不支持Node.js的crypto模块，这里提供基本的替代实现
 */

// 将字符串转换为字节数组
function stringToBytes(str) {
    const bytes = [];
    for (let i = 0; i < str.length; i++) {
        bytes.push(str.charCodeAt(i) & 0xff);
    }
    return bytes;
}

// 将字节数组转换为十六进制字符串
function bytesToHex(bytes) {
    const hex = [];
    for (let i = 0; i < bytes.length; i++) {
        hex.push((bytes[i] >>> 4).toString(16));
        hex.push((bytes[i] & 0xF).toString(16));
    }
    return hex.join('');
}

// SHA-256实现 (完全自定义实现，不依赖wx.sha256)
function sha256(data) {
    // 微信小程序不提供sha256，使用完全自定义实现
    try {
        // 简化版SHA256实现
        console.log('使用完全自定义SHA256，仅用于开发环境');
        return customSHA256(data);
    } catch (error) {
        console.error('SHA256计算失败:', error);
        // 降级到简单的哈希
        if (typeof data === 'string') {
            return simpleHash(data);
        }
        return simpleHash(JSON.stringify(data));
    }
}

// 简单的哈希函数，仅用于非安全场景
function simpleHash(str) {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
        const char = str.charCodeAt(i);
        hash = ((hash << 5) - hash) + char;
        hash = hash & hash; // 转换为32位整数
    }
    return hash.toString(16);
}

// 简化版的SHA256实现，仅用于开发测试
// 注: 这不是标准的SHA256实现，生产环境应该使用服务端签名
function customSHA256(input) {
    // 确保输入是字符串
    const data = typeof input === 'string' ? input : JSON.stringify(input);

    // 初始哈希值 (简化版)
    const K = [
        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5
    ];

    // 初始哈希状态
    let h0 = 0x6a09e667;
    let h1 = 0xbb67ae85;
    let h2 = 0x3c6ef372;
    let h3 = 0xa54ff53a;
    let h4 = 0x510e527f;
    let h5 = 0x9b05688c;
    let h6 = 0x1f83d9ab;
    let h7 = 0x5be0cd19;

    // 将输入转为字节数组
    const bytes = [];
    for (let i = 0; i < data.length; i++) {
        bytes.push(data.charCodeAt(i) & 0xFF);
    }

    // 混合函数
    function mix(h, input) {
        let a = h0, b = h1, c = h2, d = h3;
        let e = h4, f = h5, g = h6, h_val = h7;

        // 简化的混合操作
        for (let i = 0; i < input.length; i++) {
            const temp1 = (h_val + input[i] + K[i % 8]) & 0xFFFFFFFF;
            const temp2 = (a + b) & 0xFFFFFFFF;

            h_val = g;
            g = f;
            f = e;
            e = (d + temp1) & 0xFFFFFFFF;
            d = c;
            c = b;
            b = a;
            a = (temp1 + temp2) & 0xFFFFFFFF;
        }

        h0 = (h0 + a) & 0xFFFFFFFF;
        h1 = (h1 + b) & 0xFFFFFFFF;
        h2 = (h2 + c) & 0xFFFFFFFF;
        h3 = (h3 + d) & 0xFFFFFFFF;
        h4 = (h4 + e) & 0xFFFFFFFF;
        h5 = (h5 + f) & 0xFFFFFFFF;
        h6 = (h6 + g) & 0xFFFFFFFF;
        h7 = (h7 + h_val) & 0xFFFFFFFF;
    }

    // 处理数据块
    mix([h0, h1, h2, h3, h4, h5, h6, h7], bytes);

    // 将哈希值转为十六进制字符串
    function toHex(val) {
        let hex = '';
        for (let i = 0; i < 8; i++) {
            const byte = (val >>> (i * 4)) & 0xF;
            hex += byte.toString(16);
        }
        return hex;
    }

    // 返回最终哈希值
    return toHex(h0) + toHex(h1) + toHex(h2) + toHex(h3) +
        toHex(h4) + toHex(h5) + toHex(h6) + toHex(h7);
}

// 创建Hash对象
class Hash {
    constructor(algorithm) {
        this.algorithm = algorithm;
        this.data = '';
    }

    update(data) {
        if (typeof data === 'string') {
            this.data += data;
        } else if (data instanceof ArrayBuffer) {
            const view = new Uint8Array(data);
            let str = '';
            for (let i = 0; i < view.length; i++) {
                str += String.fromCharCode(view[i]);
            }
            this.data += str;
        }
        return this;
    }

    digest(encoding = 'hex') {
        if (this.algorithm === 'sha256') {
            const hash = wx.sha256(this.data); // 使用正确的SHA-256
            if (encoding === 'hex') {
                return hash;
            }
            return stringToBytes(hash);
        } else if (this.algorithm === 'sha1') {
            const hash = wx.sha1(this.data);
            if (encoding === 'hex') {
                return hash;
            }
            return stringToBytes(hash);
        }
        throw new Error(`不支持的哈希算法: ${this.algorithm}`);
    }
}

// 创建HMAC对象 - 标准实现
class Hmac {
    constructor(algorithm, key) {
        this.algorithm = algorithm;
        this.key = key;
        this.data = '';
    }

    update(data) {
        if (typeof data === 'string') {
            this.data += data;
        } else if (data instanceof ArrayBuffer) {
            const view = new Uint8Array(data);
            let str = '';
            for (let i = 0; i < view.length; i++) {
                str += String.fromCharCode(view[i]);
            }
            this.data += str;
        }
        return this;
    }

    digest(encoding = 'hex') {
        // 基于RFC 2104的HMAC实现
        const blockSize = 64; // SHA-256的块大小为64字节
        let key = this.key;

        // 如果密钥长度大于块大小，使用哈希处理
        if (key.length > blockSize) {
            key = this.algorithm === 'sha256' ? wx.sha256(key) : wx.sha1(key);
        }

        // 如果密钥长度小于块大小，用0填充
        while (key.length < blockSize) {
            key += '\0';
        }

        // 创建内外填充
        const outerPadding = stringToBytes(key).map(b => b ^ 0x5C);
        const innerPadding = stringToBytes(key).map(b => b ^ 0x36);

        // 计算内部哈希
        const innerHash = this.algorithm === 'sha256'
            ? wx.sha256(String.fromCharCode(...innerPadding) + this.data)
            : wx.sha1(String.fromCharCode(...innerPadding) + this.data);

        // 计算外部哈希
        const result = this.algorithm === 'sha256'
            ? wx.sha256(String.fromCharCode(...outerPadding) + innerHash)
            : wx.sha1(String.fromCharCode(...outerPadding) + innerHash);

        if (encoding === 'hex') {
            return result;
        }

        return stringToBytes(result);
    }
}

module.exports = {
    createHash: function (algorithm) {
        return new Hash(algorithm);
    },

    createHmac: function (algorithm, key) {
        return new Hmac(algorithm, key);
    },

    // 直接计算哈希值的工具函数
    sha1: function (data) {
        return wx.sha1(data);
    },

    sha256: sha256
}; 